/**
Based on sample code shipped with libedit.
Will need work to integrate with ICU, which
appears to seg on Unicode characters as is :)
**/

// Should (input ...) use libedit too, by default?

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

#include <histedit.h>

#include "interpreter.h"
#include <unicode/ustdio.h>

#include <gc/gc.h>

#include "string-buffer.h"

int continued_line = 0;
static EditLine *global_line_editor = NULL;

#define BUFFER_SIZE 1024
#define CMP_NEQ(X) (0 != (X))

static char * get_prompt(EditLine *line_editor)
{
  static char first[] = "> ";
  static char next[] = "- ";
  return (continued_line ? next : first);
}

value_t *run_function(scope_t *scope, function_t *function, handler_t *handler);

void repl(char *program_name)
{

  History *history_ptr;
  HistEvent history_event;

  // Register signal handlers
  // <do it>

  // Initialise history
  history_ptr = history_init();
  // Set history size
  history(history_ptr, &history_event, H_SETSIZE, 100);

  // Initialise the line editor
  global_line_editor = el_init(program_name, stdin, stdout, stderr);

  // Set the history interface
  el_set(global_line_editor, EL_HIST, history, history_ptr);

  // Default to Emacs mode
  el_set(global_line_editor, EL_EDITOR, "emacs"); 

  // Set prompt function
  el_set(global_line_editor, EL_PROMPT, get_prompt); 

  // Read-Evaluate-Print Loop

  UFILE *u_stdout = u_finit(stdout, NULL, NULL);
  UFILE *u_stderr = u_finit(stderr, NULL, NULL);

  scope_t *builtins = construct_builtins();
  scope_t *environment = make_scope(builtins,NULL,NULL,NULL);

  while(1)
  {
    string_buffer_t *source_buffer = make_string_buffer(BUFFER_SIZE);
    char *line_buffer;
    int characters_read = 0, total_read = 0;
    continued_line = 0;
    while((line_buffer = (char *)el_gets(global_line_editor, &characters_read)) != 0 && characters_read > 1)
    {
      history(history_ptr, &history_event, continued_line ? H_APPEND : H_ENTER, line_buffer);
      string_buffer_append(source_buffer, to_unicode(line_buffer));
      total_read += characters_read;
      continued_line = 1;
      characters_read = 0;
    }

    // Got end of file
    if(0 == characters_read)
      break;

    // Got no input
    if(1 == total_read)
      continue;


    handler_t handler;
    handler.stack = make_generic_list(NULL);
    handler.status = setjmp(handler.jump);
    
    if(handler.status)
    {
      show_exception(&handler);
      continue;
    }
    UChar *final = string_buffer_finalize(source_buffer);
    UFILE *source_file = u_fstropen(final, total_read, NULL);
    value_t *main = (value_t*)parse(source_file,to_unicode("<repl>"),&handler);
    
    u_fflush(source_file);
    u_fclose(source_file);
    main->function.arguments = 0;

 
    value_t *result = (value_t*)run_function(environment,&(main->function), &handler);
    UChar *none_string = to_unicode("none");
    // Fix this to use compare_equal
    if(result && (!has_type(result, type_tag) || CMP_NEQ(compare(result,(value_t*)make_tag(none_string)))))
    {
      u_fprintf(u_stdout,"%S\n",show_value(result));
    }

  }

  u_fclose(u_stdout);
  // Clean up the line editor
  el_end(global_line_editor);
}
